// CSE571 - player-main.cpp
// Authors: Jonathan Wald, Daniel Sarfati, Guangle Fan
// This file holds the main function that is run by the client program.

#include <iostream>
#include "stdio.h"

#include "ace/Auto_Ptr.h"
#include "ace/Connector.h"

#include "ace/INET_Addr.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Connector.h"
#include "ace/SOCK_Stream.h"
#include "ace/Signal.h"

#include "game-manager.h"
#include "player-game.h"
#include "player.h"
#include "signal-handler.h"

class PlayerSvcHandler;

typedef ACE_Connector<PlayerSvcHandler,ACE_SOCK_CONNECTOR>
    PlayerConnector;

const int MTU = 1500;
extern char buffer[];

int parse_file(char* filename);

int main(int argc, char* argv[]) {

   GameManager* manager = GameManager::instance();
   string player_name;
   bool saw_file_flag = false;
   
   const int NAME_FLAG = 0, FILE_FLAG = 1;
   int flag;
    
   bool parse_error = false;
   string error_msg;
   
   // Process the command line switches.  Look at every second arg for
   // a recognizable flag.
   for (int i = 1; i < argc; i += 2) {
      if (!strcmp("-n", argv[i])) flag = NAME_FLAG;
      else if (!strcmp("-f", argv[i])) flag = FILE_FLAG;
      else {
         parse_error = true;
         error_msg = "Unknown flag.";
         break;
      }
      
      if ((i+1) == argc) {     // this means we don't have an even number of tokens -> parameter or flag must be missing
         parse_error = true;
         error_msg = "Missing parameter or flag.";
         break;
      }
      
      if ((strlen(argv[i+1]) == 0) || (argv[i+1][0] == '-')) {
         parse_error = true;
         error_msg = "Missing parameter for flag.";
         break;
      }
    
      switch (flag) {
         case NAME_FLAG:
            player_name = argv[i+1];
            break;
        case FILE_FLAG:
            saw_file_flag = true;
            if (manager->parse_file(argv[i+1]) != 0) { 
               parse_error = true; 
               error_msg = "Could not parse defintion file.";
            }
            break;
      }
   }
   
   if (player_name.size() == 0) {
      parse_error = true;
      error_msg = "Player must have name.";
   }
   else manager->set_name(player_name);
   
   if (!saw_file_flag) {
      parse_error = true;
      error_msg = "Must enter a definition file.";
   }
   
   if (parse_error) {
      std::cout << "ERROR: " << error_msg << std::endl;
      std::cout << "Usage: client -n <player name> -f <definition file> " << std::endl;
      return -1;
   }
   
   PlayerConnector player_connector(ACE_Reactor::instance());
   
   // keep track of the number of open connections so we can
   // kill the client if no connections were able to be opened
   int num_open_connections = manager->num_games();
   
   for (unsigned int i = 0; i < manager->num_games(); ++i) {
      PlayerGame* game = manager->get_game(i);
      ACE_INET_Addr peer_addr;
      
      if (peer_addr.set(game->get_port(), game->get_host().c_str()) == -1) {
         std::cout << "Unable to set server address for " << game->get_host() << ":" << game->get_port() << std::endl;
         num_open_connections--;
         continue;
      }
      
      peer_addr.addr_to_string (buffer, MTU);
      std::cout << "Address and port: " << buffer << std::endl;

      PlayerSvcHandler* connector_handler = &(game->handler);
      if (player_connector.connect (connector_handler, peer_addr) == -1) {
         std::cout << "Couldn't connect to server.\n" << std::endl;
         num_open_connections--;
      }
   }
   
   if (num_open_connections == 0) return -1;     // kill the client if no connections were able to be opened
   
   // Implement signal handler.                                                 
   ACE_Sig_Action sa;
   sa.register_action (SIGINT);
   SigHandler sh (ACE_Reactor::instance());

   while (!SigHandler::sigint_fired()) {
      ACE_Reactor::instance()->handle_events();
   }

   if (GameManager::instance() != NULL) {
      delete GameManager::instance();
   }
   
   return 0;
}

